package com.bingxue.edu.management.education.service;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.json.JSONUtil;
import com.alibaba.excel.EasyExcel;
import com.bingxue.edu.framework.common.constant.CacheConstants;
import com.bingxue.edu.framework.common.util.ValidationUtils;
import com.bingxue.edu.framework.exception.BusinessException;
import com.bingxue.edu.framework.mybatis.base.BaseService;
import com.bingxue.edu.framework.redis.RedisUtils;
import com.bingxue.edu.management.education.mapper.EnrollPermissionMapper;
import com.bingxue.edu.management.education.model.entity.ClassInfo;
import com.bingxue.edu.management.education.model.entity.EnrollPermission;
import com.bingxue.edu.management.education.model.entity.Student;
import com.bingxue.edu.management.education.model.req.EnrollPermissionImportReq;
import com.bingxue.edu.management.education.model.req.EnrollPermissionImportRowReq;
import com.bingxue.edu.management.education.model.req.EnrollPermissionReq;
import com.bingxue.edu.management.education.model.resp.EnrollPermissionImportParseResp;
import com.bingxue.edu.management.education.model.resp.EnrollPermissionResp;
import com.mybatisflex.core.query.QueryCondition;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.time.Duration;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

import static com.bingxue.edu.management.education.model.entity.table.ClassInfoTableDef.CLASS_INFO;
import static com.bingxue.edu.management.education.model.entity.table.EnrollPermissionTableDef.ENROLL_PERMISSION;

/**
 * 报名权限业务类
 *
 * @author zq
 * @since 2024/08/22
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class EnrollPermissionService extends BaseService<EnrollPermissionMapper, EnrollPermission> {

    public static final Integer MIN_LEVEL = 0;

    @Resource
    @Lazy
    private StudentService studentService;

    @Transactional(rollbackFor = Exception.class)
    public void createPermission(EnrollPermissionReq req) {
        EnrollPermission existPermission = this.queryChain()
                .where(ENROLL_PERMISSION.STUDENT_ID.eq(req.getStudentId()))
                .and(ENROLL_PERMISSION.SUBJECT.eq(req.getSubject()))
                .and(ENROLL_PERMISSION.ADMISSION_YEAR.eq(req.getAdmissionYear()))
                .one();
        if (existPermission == null) {
            EnrollPermission newPermission = this.copy(req);
            this.save(newPermission);
        } else if (existPermission.getClassLevel() < req.getClassLevel()) {
            existPermission.setClassLevel(req.getClassLevel());
            this.updateById(existPermission);
        }
        log.info("创建选课权限成功, {}", req);
    }

    public List<EnrollPermission> getPermissionListByStudentId(String studentId, String subject) {
        List<EnrollPermission> permissionList = this.queryChain()
                .where(ENROLL_PERMISSION.STUDENT_ID.eq(studentId))
                .and(ENROLL_PERMISSION.SUBJECT.eq(subject))
                .list();
        if (permissionList.isEmpty()) {
            EnrollPermission permission = new EnrollPermission();
            permission.setStudentId(studentId);
            permission.setSubject(subject);
            permission.setClassLevel(MIN_LEVEL);
            permission.setAdmissionYear(LocalDate.now().getYear());
            permissionList.add(permission);
        }
        return permissionList;
    }

    public List<EnrollPermissionResp> getPermissionListByStudentId(String studentId) {
        return this.queryChain().where(ENROLL_PERMISSION.STUDENT_ID.eq(studentId)).listAs(EnrollPermissionResp.class);
    }

    public boolean hasPermission(String studentId, ClassInfo classInfo) {
        if(classInfo.getClassLevelLimit() == null && classInfo.getAdmissionYearLimit() == null) {
            return true;
        }
        return this.queryChain()
                .where(ENROLL_PERMISSION.STUDENT_ID.eq(studentId))
                .and(ENROLL_PERMISSION.SUBJECT.eq(classInfo.getSubject()))
                .and(ENROLL_PERMISSION.ADMISSION_YEAR.le(classInfo.getAdmissionYearLimit()))
                .and(ENROLL_PERMISSION.CLASS_LEVEL.ge(classInfo.getClassLevelLimit()))
                .exists();
    }

    /**
     * 判断选课权限是否满足要求
     * @param studentId 学生id
     * @param classInfo 班级信息
     */
    public void checkPermission(String studentId, ClassInfo classInfo) {
        if (!hasPermission(studentId, classInfo)) {
            throw new BusinessException("没有[%s]的选课权限".formatted(classInfo.getName()));
        }
    }

    /**
     * 更新权限
     * 如果没有权限则创建
     * 如果存在相同科目和年份的权限，则取最大值
     */
    @Transactional(rollbackFor = Exception.class)
    public void updatePermission(String studentId, ClassInfo classInfo) {
        EnrollPermission existPermission = this.queryChain()
                .where(ENROLL_PERMISSION.STUDENT_ID.eq(studentId))
                .and(ENROLL_PERMISSION.SUBJECT.eq(classInfo.getSubject()))
                .and(ENROLL_PERMISSION.ADMISSION_YEAR.eq(classInfo.getAdmissionYearLimit()))
                .one();
        if (existPermission == null) {
            EnrollPermission newPermission = new EnrollPermission();
            newPermission.setStudentId(studentId);
            newPermission.setSubject(classInfo.getSubject());
            newPermission.setAdmissionYear(classInfo.getAdmissionYearLimit());
            newPermission.setClassLevel(classInfo.getClassLevelLimit());
            this.save(newPermission);
        } else if (existPermission.getClassLevel() < classInfo.getClassLevelLimit()) {
            existPermission.setClassLevel(classInfo.getClassLevelLimit());
            this.updateById(existPermission);
        }
    }

    /**
     * 解析导入的数据
     * @param file 文件
     */
    public EnrollPermissionImportParseResp parseImportEnrollPermission(MultipartFile file) {
        EnrollPermissionImportParseResp enrollPermissionImportResp = new EnrollPermissionImportParseResp();
        List<EnrollPermissionImportRowReq> enrollPermissionRowList;

        // 读取表格数据
        try {
            enrollPermissionRowList = EasyExcel.read(file.getInputStream())
                    .head(EnrollPermissionImportRowReq.class)
                    .sheet()
                    .headRowNumber(1)
                    .doReadSync();
        } catch (Exception e) {
            log.error("用户导入数据文件解析异常：", e);
            throw new BusinessException("数据文件解析异常");
        }
        enrollPermissionImportResp.setTotalRows(enrollPermissionRowList.size());
        if (CollUtil.isEmpty(enrollPermissionRowList)) {
            throw new BusinessException("数据文件格式错误");
        }

        // 校验数据库是否存在重复数据
//        for (EnrollPermissionImportRowReq row : validUserRowList) {
//            QueryWrapper studentQueryWrapper = QueryWrapper.create()
//                            .select(STUDENT.ID)
//                            .from(STUDENT)
//                            .where(STUDENT.PARENT_PHONE.eq(row.getParentPhone()))
//                            .and(STUDENT.NAME.eq(row.getStudentName()));
//            String studentId = studentService.getOneAs(studentQueryWrapper,String.class);
//            QueryWrapper enrollPermissionQueryWrapper = QueryWrapper.create()
//                            .select(ENROLL_PERMISSION.ALL_COLUMNS)
//                            .from(ENROLL_PERMISSION)
//                            .where(ENROLL_PERMISSION.STUDENT_ID.eq(studentId))
//                            .and(ENROLL_PERMISSION.ADMISSION_YEAR.eq(row.getAdmissionYear()))
//                            .and(ENROLL_PERMISSION.SUBJECT.eq(row.getSubject()))
//                            .and(ENROLL_PERMISSION.CLASS_LEVEL.eq(row.getClassLevel()));
//            boolean isExists = this.exists(enrollPermissionQueryWrapper);
//            ValidationUtils.throwIf(isExists, "数据库存在重复数据，请检查数据");
//        }


        //转换为实体对象并校验字段
        List<EnrollPermission> importEnrollPermissionEntities = transformReq2EntityAndValidate(enrollPermissionRowList,enrollPermissionImportResp);

        // 设置导入会话并缓存数据，有效期10分钟
        String importKey = UUID.fastUUID().toString(true);
        RedisUtils.set(CacheConstants.DATA_IMPORT_KEY + importKey, JSONUtil.toJsonStr(importEnrollPermissionEntities), Duration
                .ofMinutes(10));
        enrollPermissionImportResp.setImportKey(importKey);

        return enrollPermissionImportResp;
    }

    /**
     * 过滤掉包含空字段的行
     * @param enrollPermissionRowList 所有excel行
     * @return 不包含空字段的行
     */
    private List<EnrollPermissionImportRowReq> filterErrorEnrollPermissionImportData(List<EnrollPermissionImportRowReq> enrollPermissionRowList) {
        return enrollPermissionRowList.stream()
                .filter(obj -> obj.getParentPhone() != null && obj.getStudentName() != null && obj.getSubject() != null && obj.getAdmissionYear() != null && obj.getClassLevel() != null )
                .collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public Void importEnrollPermission(EnrollPermissionImportReq req) {
        // 校验导入会话是否过期
        List<EnrollPermission> importEnrollPermissionList;
        try {
            String data = RedisUtils.get(CacheConstants.DATA_IMPORT_KEY + req.getImportKey());
            importEnrollPermissionList = JSONUtil.toList(data, EnrollPermission.class);
            ValidationUtils.throwIf(CollUtil.isEmpty(importEnrollPermissionList), "导入已过期，请重新上传");
        } catch (Exception e) {
            log.error("导入异常:", e);
            throw new BusinessException("导入已过期，请重新上传");
        }
        //导入学生权限
        for (EnrollPermission enrollPermission :importEnrollPermissionList){
            EnrollPermissionReq createReq = new EnrollPermissionReq();
            BeanUtils.copyProperties(enrollPermission,createReq);
            this.createPermission(createReq);
        }


//        //重复行数据库查询
//        List<EnrollPermission> existPermissionsEntities = listExist(importEnrollPermissionList);
//
//        //过滤重复的数据:importEnrollPermissionEntityList - existPermissionsEntity
//        List<EnrollPermission> filteredEnrollPermission = importEnrollPermissionList.stream()
//                .filter(entity -> existPermissionsEntities.stream()
//                        .noneMatch(existing -> entity.getSubject().equals(existing.getSubject())
//                                && entity.getAdmissionYear().equals(existing.getAdmissionYear())
//                                && entity.getSubject().equals(existing.getSubject())))
//                .collect(Collectors.toList());
//
//        Integer returnTotalRows =0;
//        Integer returnUpdateRows =0;
//        Integer returnInsertRows =0;
//        //根据更新策略更新数据
//        ImportPolicyEnum duplicateDataImportPolicy = req.getDuplicateDataImportPolicy();
//            if (ImportPolicyEnum.SKIP.equals(duplicateDataImportPolicy)) {
//                //遇到重复直接跳过该行
//                this.saveBatch(filteredEnrollPermission);
//                returnTotalRows = filteredEnrollPermission.size();
//                returnInsertRows = filteredEnrollPermission.size();
//            } else if (ImportPolicyEnum.UPDATE.equals(duplicateDataImportPolicy)) {
//                //遇到重复的则直接更新这行
//                this.saveBatch(filteredEnrollPermission);
//                this.updateBatch(existPermissionsEntities);
//
//                returnTotalRows = filteredEnrollPermission.size() + existPermissionsEntities.size();
//                returnUpdateRows = existPermissionsEntities.size();
//                returnInsertRows = filteredEnrollPermission.size();
//            } else if (ImportPolicyEnum.EXIT.equals(duplicateDataImportPolicy)) {
//                if (existPermissionsEntities.size() != 0)
//                    throw new BusinessException("退出策略执行:遇到重复行,导入退出");
//            }

        RedisUtils.delete(CacheConstants.DATA_IMPORT_KEY + req.getImportKey());
        return null;
    }

    /**
     * 将请求对象转换为实体对象并且校验字段是否为空和重复
     * @param importEnrollPermissionRowReqs 行数据请求对象
     * @param enrollPermissionImportResp 返回数据
     * @return  行数据请求对象转换后的实体对象
     */
    private List<EnrollPermission> transformReq2EntityAndValidate(List<EnrollPermissionImportRowReq> importEnrollPermissionRowReqs, EnrollPermissionImportParseResp enrollPermissionImportResp) {
        // 过滤包含空字段的行无效数据
        List<EnrollPermissionImportRowReq> validatedImportEnrollPermissionRowReqs = filterErrorEnrollPermissionImportData(importEnrollPermissionRowReqs);
        enrollPermissionImportResp.setValidRows(validatedImportEnrollPermissionRowReqs.size());
        ValidationUtils.throwIf(CollUtil.isEmpty(validatedImportEnrollPermissionRowReqs),"数据文件格式错误");

        // 检测表格内数据是否存在重复
        Set<EnrollPermissionImportRowReq> seenRows = new HashSet<>();
        boolean hasDuplicateRow = validatedImportEnrollPermissionRowReqs.stream()
                .anyMatch(row -> row != null && !seenRows.add(row));
        ValidationUtils.throwIf(hasDuplicateRow, "存在重复数据行，请检测数据");

        List<EnrollPermission> enrollPermissions = new ArrayList<>();
        for (EnrollPermissionImportRowReq enrollPermissionImportRowReq:validatedImportEnrollPermissionRowReqs){
            EnrollPermission enrollPermission = new EnrollPermission();
            enrollPermission.setSubject(enrollPermissionImportRowReq.getSubject());
            enrollPermission.setClassLevel(enrollPermissionImportRowReq.getClassLevel());
            enrollPermission.setAdmissionYear(enrollPermissionImportRowReq.getAdmissionYear());
            //Todo::班级类型id
            //enrollPermission.setClassTypeId();
            Student student = studentService.getByNameAndPhone(enrollPermissionImportRowReq.getStudentName(),enrollPermissionImportRowReq.getParentPhone());
            ValidationUtils.throwIfNull(student,"没有学生名称[{}]和家长电话 [{}]对应的学生",enrollPermissionImportRowReq.getStudentName(),enrollPermissionImportRowReq.getParentPhone());
            enrollPermission.setStudentId(student.getId());
            enrollPermissions.add(enrollPermission);
        }
        return enrollPermissions;
    }

    /**
     * 构造权限过滤查询条件
     */
    public QueryCondition buildPermissionFilterCondition(String studentId, String subject) {
        List<EnrollPermission> permissionList = this.getPermissionListByStudentId(studentId, subject);
        QueryCondition condition = null;
        for (EnrollPermission permission : permissionList) {
            if (condition == null) {
                condition = CLASS_INFO.ADMISSION_YEAR_LIMIT.eq(permission.getAdmissionYear()).and(CLASS_INFO.CLASS_LEVEL_LIMIT.le(permission.getClassLevel()));
            } else {
                condition = condition.or(CLASS_INFO.ADMISSION_YEAR_LIMIT.eq(permission.getAdmissionYear()).and(CLASS_INFO.CLASS_LEVEL_LIMIT.le(permission.getClassLevel())));
            }
        }
        return condition;
    }
}
